package com.coderside.fragment.thread.ABC;

import java.util.concurrent.CountDownLatch;

/**
 * 多线程循环打印ABCABC
 * 
 * @author cheney
 * 
 * 理论部分： 首先肯定是要开启3个线程的。3个线程分别循环打印A，B，C三个字母。
 * 这里的关键是要控制三个线程的同步问题，一个线程在打印输出，而其他的2个线程需要等待挂起状态。然后轮到下一个线程打印输出，而本线程需要是挂起状态。
 * 
 * 分析： 1.三个线程需要同步，这时可以想到用一个共用的变量来承担这个控制的角色。这个变量在java里面可以是object lock来定义。
 * 2.三个线程可以同步了，但是要如何按照顺序来打印呢，而不是出现ACB等这样的情况呢。这时可以想到也是一个都可以访问的变量的控制，可以用一个int的值来确定这个。然后令这个三个线程分别表示为1，2，3.
 * 这样当int的值增加1并对3取模时，可以顺利的移到下一个线程，达到循环控制。
 * 
 */
public class ThreadPrintABC_1 {

	/**
	 * 使用锁需要注意的三点：使用其他的方式来取代独占锁、减少持有锁的时间、减低请求锁的频率
	 * 
	 */
	Object lock = new Object(); // 共用的锁
	int count = 0; // 计数
	int circleNum = 100;
	final CountDownLatch countdownlatch = new CountDownLatch(3 * circleNum);

	public static void main(String[] args) {
		new ThreadPrintABC_1().processABC();
	}

	private void processABC() {
		long a = System.currentTimeMillis();
		printTask a1 = new printTask("A", 0);
		printTask b2 = new printTask("B", 1);
		printTask c3 = new printTask("C", 2);
		new Thread(a1).start();
		new Thread(b2).start();
		new Thread(c3).start();
		try {
			countdownlatch.await();
			long b = System.currentTimeMillis();
			System.out.println(b - a);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	class printTask implements Runnable {
		String mName = "";
		int mId = 0;

		public printTask(String name, int id) {
			mName = name;
			mId = id;
		}

		public void run() {
			for (int i = 0; i < circleNum; i++) {
				synchronized (lock) {
					while (true) {
						if (count % 3 == mId) {
							System.out.print(mName);
							count++;
							countdownlatch.countDown();
							lock.notifyAll();
							break;
						} else {
							try {
								lock.wait();
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
				}
			}
		}
	}
}